package com.easylinkin.linkappapi.common.utils.safeAndQuality;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.easylinkin.linkappapi.messagecenter.dao.MessageCenterMapper;
import com.easylinkin.linkappapi.messagecenter.entity.MessageCenter;
import com.easylinkin.linkappapi.messagecenter.entity.enumType.messageTypeEnum;
import com.easylinkin.linkappapi.quality.dto.QualityQuestionInfoDto;
import com.easylinkin.linkappapi.quality.entity.QualityConfig;
import com.easylinkin.linkappapi.quality.mapper.QualityConfigMapper;
import com.easylinkin.linkappapi.quality.mapper.QualityQuestionInfoMapper;
import com.easylinkin.linkappapi.safe.dao.HiddenConfigMapper;
import com.easylinkin.linkappapi.safe.dao.HiddenDangerMapper;
import com.easylinkin.linkappapi.safe.dto.HiddenDangerDTO;
import com.easylinkin.linkappapi.safe.entity.HiddenConfig;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Description 安全和质量消息通知定时任务
 * @Author kan yuanfeng
 * @Date 2023/7/11 14:05
 */
@Component
public class SafeAndQualityTimer {
    @Autowired
    private HiddenConfigMapper hiddenConfigMapper;
    @Autowired
    private QualityConfigMapper qualityConfigMapper;
    @Autowired
    private HiddenDangerMapper hiddenDangerMapper;
    @Autowired
    private QualityQuestionInfoMapper questionInfoMapper;
    @Autowired
    private SendMsgUtils sendMsgUtils;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MessageCenterMapper messageCenterMapper;

    //定义一个缓存key
    private String noticeKey = "notice:";

    //安全超期的消息标题
    String hiddenOverTitle = "安全隐患超期未闭合";

    //质量整改超期的消息标题
    String qualityRectifyOverTitle = "质量问题整改超期未闭合";

    //质量复核超期的消息标题
    String qualityCheckOverTitle = "质量问题复核超期未闭合";

    private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(SafeAndQualityTimer.class);

    /**
     * 即将超期通知(每小时执行一次)
     */
    @Scheduled(cron = "0 0 0/1 * * ?")
    public void dueNotice(){
        try {
            LOGGER.info("------超期即将到期通知----------checkWarning------start-----");
            //安全通知
            hiddenHueNotice();
            //质量通知
            qualityHueNotice();
            LOGGER.info("------超期即将到期通知----------checkWarning------end-----");
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.info("------超期即将到期通知----------checkWarning------异常-----");
        }
    }

    /**
     * 超期通知(每天9点执行)
     */
    @Scheduled(cron = "0 0 9 * * ?")
    public void overNotice(){
        try {
            LOGGER.info("------超期通知----------checkWarning------start-----");
            Date date = new Date();
            //安全通知
            hiddenOverNotice(date);
            //质量通知
            qualityOverNotice(date);
            LOGGER.info("------超期通知----------checkWarning------end-----");
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.info("------超期通知----------checkWarning------异常-----");
        }
    }

    /**
     * 安全消息即将超期通知
     */
    private void hiddenHueNotice() {
        String KeyPre = noticeKey+"h";
        //即将复合即将超期的数据
        List<HiddenDangerDTO> hiddenDangerDTOS = hiddenDangerMapper.findHueList();
        if (CollectionUtil.isNotEmpty(hiddenDangerDTOS)){
            hiddenDangerDTOS.forEach(h->{
                //判断是否已经执行过,执行过就不再执行
                Boolean aBoolean = redisTemplate.hasKey(KeyPre + h.getId());
                if (!aBoolean){
                    //判断是整改还是复查
                    boolean flag = Integer.valueOf(0).equals(h.getStatus());
                    String title = (flag?"整改":"复查")+"即将超期";
                    String ownerId = (flag?h.getRectifyUid():h.getCheckUid())+"";
                    sendMsgUtils.saveHiddenMessage(title,"安全隐患:"+h.getContent(),ownerId,h,true);
                    //放入redis中。并且24小时过期
                    redisTemplate.opsForValue().set(KeyPre+h.getId(),true,1, TimeUnit.DAYS);
                }
            });
        }
    }

    /**
     * 质量消息即将超期通知
     */
    private void qualityHueNotice() {
        String KeyPre = noticeKey+"q";
        //即将复合即将超期的数据
        List<QualityQuestionInfoDto> questionInfoDtos = questionInfoMapper.findHueList();
        if (CollectionUtil.isNotEmpty(questionInfoDtos)){
            questionInfoDtos.forEach(q->{
                //判断是否已经执行过,执行过就不再执行
                Boolean aBoolean = redisTemplate.hasKey(KeyPre + q.getId());
                if (!aBoolean){
                    //判断是整改还是复查
                    boolean flag = Integer.valueOf(1).equals(q.getQuestionState());
                    String title = (flag?"整改":"复核")+"即将超期";
                    String ownerId = (flag?q.getRectifierId():q.getReviewerId())+"";
                    sendMsgUtils.saveQualityMessage(title,"质量:"+q.getQuestionContent(),ownerId,q,true);
                    //放入redis中。并且24小时过期
                    redisTemplate.opsForValue().set(KeyPre+q.getId(),true,1, TimeUnit.DAYS);
                }
            });
        }
    }

    /**
     * 安全消息超期通知
     * @param date
     */
    private void hiddenOverNotice(Date date) {
        List<HiddenConfig> hiddenConfigs = hiddenConfigMapper.selectList(new QueryWrapper<>());
        if (CollectionUtil.isNotEmpty(hiddenConfigs)){
            //收集项目tenantId
            List<String> tenantIds = hiddenConfigs.stream().map(h -> h.getTenantId()).collect(Collectors.toList());
            //查询已超期的安全隐患
            List<HiddenDangerDTO> hiddenDangerDTOS = hiddenDangerMapper.findOverByTenantIds(tenantIds);
            if (CollectionUtil.isNotEmpty(hiddenDangerDTOS)){
                //查询已经发送过超期通知的数据
                List<String> linkIds = hiddenDangerDTOS.stream().map(h -> h.getId()).collect(Collectors.toList());
                List<String> msgLinkIds = findMsg(messageTypeEnum.DANGER.ordinal(), hiddenOverTitle, linkIds);
                //分组
                Map<String, List<HiddenDangerDTO>> listMap = hiddenDangerDTOS.stream().collect(Collectors.groupingBy(HiddenDangerDTO::getTenantId));
                listMap.forEach((k,v) ->{
                    List<HiddenConfig> configs = hiddenConfigs.stream().filter(h -> k.equals(h.getTenantId())).collect(Collectors.toList());
                    if (CollectionUtil.isNotEmpty(configs)){
                        HiddenConfig hiddenConfig = configs.get(0);
                        //超期天数上报
                        if (Boolean.TRUE.equals(hiddenConfig.getTaskOver())){
                            List<HiddenDangerDTO> dtos = v.stream().filter(item -> DateUtil.betweenDay(item.getRectifyEndTime(), date, true) <= hiddenConfig.getOverParam())
                                    .collect(Collectors.toList());
                            if (CollectionUtil.isNotEmpty(dtos)){
                                //发送消息
                                dtos.forEach(d->{
                                    //计算日期
                                    long day = DateUtil.betweenDay(d.getRectifyEndTime(), date, true);
                                    //判断是整改还是复查
                                    boolean flag = Integer.valueOf(0).equals(d.getStatus());
                                    String title = "隐患"+(flag?"整改":"复查")+"已超期"+day+"天";
                                    String ownerId = (flag?d.getRectifyUid():d.getCheckUid())+"";
                                    sendMsgUtils.saveHiddenMessage(title,"安全隐患:"+d.getContent(),ownerId,d,true);
                                });
                            }
                        }
                        //超期上报
                        if (Boolean.TRUE.equals(hiddenConfig.getTaskUpper()) && StringUtils.isNotBlank(hiddenConfig.getUpperParam())){
                            //判断上报生效时间是否小于或等于超时时间
                            //判断是否已经通知过
                            List<HiddenDangerDTO> dtos = v.stream().filter(item -> item.getRectifyEndTime().getTime() >= hiddenConfig.getUpperTime().getTime()
                                    && !msgLinkIds.contains(item.getId()))
                                    .collect(Collectors.toList());
                            if (CollectionUtil.isNotEmpty(dtos)){
                                //发送通知
                                dtos.forEach(d->{
                                    String[] strings = hiddenConfig.getUpperParam().split(",");
                                    Arrays.stream(strings).forEach(s ->{
                                        sendMsgUtils.saveHiddenMessage(hiddenOverTitle,"安全隐患:"+d.getContent(),s,d,true);
                                    });
                                });
                            }
                        }
                    }
                });
            }
        }
    }

    /**
     * 质量消息超期通知
     * @param date
     */
    private void qualityOverNotice(Date date) {
        List<QualityConfig> qualityConfigs = qualityConfigMapper.selectList(new QueryWrapper<>());
        if (CollectionUtil.isNotEmpty(qualityConfigs)){
            //收集项目tenantId
            List<String> tenantIds = qualityConfigs.stream().map(h -> h.getTenantId()).collect(Collectors.toList());
            //查询已超期的质量隐患
            List<QualityQuestionInfoDto> questionInfoDtos = questionInfoMapper.findOverByTenantIds(tenantIds);
            if (CollectionUtil.isNotEmpty(questionInfoDtos)){
                //查询已经发送过超期通知的数据
                List<String> linkIds = questionInfoDtos.stream().map(h -> h.getId() + "").collect(Collectors.toList());
                List<String> msgRectifyLinkIds = findMsg(messageTypeEnum.QUALITY.ordinal(), qualityRectifyOverTitle, linkIds);
                List<String> msgCheckLinkIds = findMsg(messageTypeEnum.QUALITY.ordinal(), qualityCheckOverTitle, linkIds);
                //分组
                Map<String, List<QualityQuestionInfoDto>> listMap = questionInfoDtos.stream().collect(Collectors.groupingBy(QualityQuestionInfoDto::getTenantId));
                listMap.forEach((k,v) ->{
                    List<QualityConfig> configs = qualityConfigs.stream().filter(h -> k.equals(h.getTenantId())).collect(Collectors.toList());
                    if (CollectionUtil.isNotEmpty(configs)){
                        QualityConfig qualityConfig = configs.get(0);
                        //整改
                        qualitySet(date, v, qualityConfig,1,msgRectifyLinkIds);
                        //复核
                        qualitySet(date, v, qualityConfig,2,msgCheckLinkIds);
                    }
                });
            }
        }
    }

    /**
     * 质量超期复核处理
     * @param date
     * @param list
     * @param qualityConfig
     * @param status
     */
    private void qualitySet(Date date, List<QualityQuestionInfoDto> list, QualityConfig qualityConfig,Integer status,List<String> linkIds) {
        //判断是否待整改
        boolean isRectify = Integer.valueOf(1).equals(status);
        List<QualityQuestionInfoDto> sonList = list.stream().filter(item -> status.equals(item.getQuestionState())).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(sonList)){
            //判断开关是否开启
            if ((isRectify && Boolean.TRUE.equals(qualityConfig.getRectifyOver())) || (!isRectify && Boolean.TRUE.equals(qualityConfig.getCheckOver()))){
                List<QualityQuestionInfoDto> infoDtos;
                if (isRectify){
                    infoDtos = sonList.stream().filter(item -> DateUtil.betweenDay(item.getRectifiLimitTime(), date, true) <= qualityConfig.getRectifyOverParam())
                            .collect(Collectors.toList());
                }else {
                    infoDtos = sonList.stream().filter(item -> DateUtil.betweenDay(item.getReviewLimitTime(), date, true) <= qualityConfig.getCheckOverParam())
                            .collect(Collectors.toList());
                }
                if (CollectionUtil.isNotEmpty(infoDtos)){
                    //发送消息
                    infoDtos.forEach(d->{
                        //计算日期
                        long day = DateUtil.betweenDay(d.getRectifiLimitTime(), date, true);
                        //判断是整改还是复查
                        String title = "问题"+(isRectify?"整改":"复核")+"已超期"+day+"天";
                        String ownerId = (isRectify?d.getRectifierId():d.getReviewerId())+"";
                        sendMsgUtils.saveQualityMessage(title,"质量问题:"+d.getQuestionContent(),ownerId,d,true);
                    });
                }
            }
            //超期上报
            boolean flag = (isRectify && Boolean.TRUE.equals(qualityConfig.getRectifyUpper()) && StringUtils.isNotBlank(qualityConfig.getRectifyUpperParam()))
                    || (!isRectify && Boolean.TRUE.equals(qualityConfig.getCheckUpper()) && StringUtils.isNotBlank(qualityConfig.getCheckUpperParam()));
            if (flag){
                //判断上报生效时间是否小于或等于超时时间
                List<QualityQuestionInfoDto> dtos;
                if (isRectify){
                    dtos = sonList.stream().filter(item -> item.getRectifiLimitTime().getTime() >= qualityConfig.getRectifyUpperTime().getTime()
                            && !linkIds.contains(item.getId()+""))
                            .collect(Collectors.toList());
                }else {
                    dtos = sonList.stream().filter(item -> item.getReviewLimitTime().getTime() >= qualityConfig.getCheckUpperTime().getTime()
                                    && !linkIds.contains(item.getId()+""))
                            .collect(Collectors.toList());
                }
                if (CollectionUtil.isNotEmpty(dtos)){
                    //发送通知
                    dtos.forEach(d->{
                        String[] strings = qualityConfig.getRectifyUpperParam().split(",");
                        Arrays.stream(strings).forEach(s ->{
                            sendMsgUtils.saveQualityMessage(isRectify?qualityRectifyOverTitle:qualityCheckOverTitle,"质量问题:"+d.getQuestionContent(),s,d,true);
                        });
                    });
                }
            }
        }
    }

    /**
     * 查询已经发送通知的消息
     */
    private List<String> findMsg(Integer type,String title,List<String> linkIds){
        QueryWrapper<MessageCenter> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("link_id").eq("type",type)
                .eq("title",title).in("link_id",linkIds);
        List<MessageCenter> centers = messageCenterMapper.selectList(queryWrapper);
        List<String> newLinkIds = centers.stream().map(c -> c.getLinkId()).collect(Collectors.toList());
        if (null == newLinkIds){
            newLinkIds = new ArrayList<>();
        }
        return newLinkIds;
    }
}
